home *** CD-ROM | disk | FTP | other *** search
- {************************************************************************
- * maps system memory blocks for MS/PCDOS 2.0 and higher. *
- * may work on other versions of DOS but hasn't been tested. *
- * copyright (c) 1986 K. Kokkonen, TurboPower Software. *
- * released to the public domain for personal, non-commercial use only. *
- * written 1/2/86 *
- * revised 1/10/86 for *
- * running under DOS 2.X, where block owner names are unknown *
- * revised 1/22/86 for *
- * a bug in parsing the owner name of the block *
- * a quirk in the way that the DOS PRINT buffer installs itself *
- * minor cosmetic changes *
- * telephone: 408-378-3672, CompuServe: 72457,2131. *
- * requires Turbo version 3 to compile. *
- * BE SURE to compile with mAx dynamic memory = A000. *
- * limited to environment sizes of 255 bytes (default is 128 bytes) *
- ************************************************************************}
-
- PROGRAM MapMem;
- {-look at the system memory map using DOS memory control blocks}
-
- CONST
- {set the following True to see all of the candidates for memory blocks }
- {MapMem filters out some that are uninteresting or unsupported }
- showcandidates=False;
- midblockid=$4D; {byte DOS uses to identify part of MCB chain}
- endblockid=$5A; {byte DOS uses to identify last block of MCB chain}
- maxvector=$40; {highest interrupt vector checked for trapping}
-
- TYPE
- address=RECORD
- offset,segment:Integer;
- END;
- VAR
- dosv:Byte; {the major DOS version number}
- mcbseg:Integer; {potential segment address of an MCB}
- nextseg:Integer; {computed segment address for the next MCB}
- prevseg:Integer; {segment address of the previous PSP}
- oldseg:Integer; {segment address of the previous-1 PSP}
- pspadd:Integer; {segment address of the current PSP}
- mcblen:Integer; {size of the current memory block in paragraphs}
- gotfirst:Boolean; {true after first MCB is found}
- gotlast:Boolean; {true after last MCB is found}
- idbyte:Byte; {byte that DOS uses to identify an MCB}
- vectors:ARRAY[0..maxvector] OF address ABSOLUTE 0:0;
-
- FUNCTION DOSversion:Byte;
- {-return the major version number of DOS}
- VAR
- reg:RECORD
- CASE Byte OF
- 1:(ax,bx,cx,dx,bp,si,di,ds,es,flags:Integer);
- 2:(al,ah,bl,bh,cl,ch,dl,dh:Byte);
- END;
- BEGIN
- reg.ah:=$30;
- MsDos(reg);
- DOSversion:=reg.al;
- END{dosversion};
-
- PROCEDURE ShowTheBlock(VAR mcbseg,prevseg,nextseg:Integer;
- VAR gotfirst,gotlast:Boolean);
- {-display information regarding the memory block}
- TYPE
- pathname=STRING[64];
- hexstring=STRING[4];
- VAR
- st:pathname;
-
- FUNCTION Hex(i:Integer):hexstring;
- {-return hex representation of integer}
- CONST
- hc:ARRAY[0..15] OF Char='0123456789ABCDEF';
- VAR
- l,h:Byte;
- BEGIN
- l:=Lo(i);h:=Hi(i);
- Hex:=hc[h SHR 4]+hc[h AND $F]+hc[l SHR 4]+hc[l AND $F];
- END{hex};
-
- FUNCTION Cardinal(i:Integer):Real;
- {-return an unsigned integer 0..65535}
- VAR
- r:Real;
- BEGIN
- r:=i;
- IF r<0 THEN r:=r+65536.0;
- Cardinal:=r;
- END{cardinal};
-
- FUNCTION Owner(startadd:Integer):pathname;
- {-return the name of the owner program of an MCB}
- VAR
- e:STRING[255];
- i:Integer;
- t:pathname;
-
- PROCEDURE StripPathname(VAR pname:pathname);
- {-remove leading drive or path name from the input}
- VAR
- spos,cpos,rpos:Byte;
- BEGIN
- spos:=Pos('\',pname);
- cpos:=Pos(':',pname);
- IF spos+cpos=0 THEN Exit;
- IF spos<>0 THEN BEGIN
- {find the last slash in the pathname}
- rpos:=Length(pname);
- WHILE (rpos>0) AND (pname[rpos]<>'\') DO rpos:=Pred(rpos);
- END ELSE
- rpos:=cpos;
- Delete(pname,1,rpos);
- END{strippathname};
-
- BEGIN
- {get the environment string to scan}
- e[0]:=#255;
- Move(Mem[startadd:0],e[1],255);
-
- {find end of the standard environment}
- i:=Pos(#0#0,e);
- IF i=0 THEN BEGIN
- {something's wrong, exit gracefully}
- Owner:='';
- Exit;
- END;
-
- {end of environment found, get the program name that follows it}
- t:='';
- i:=i+3; {skip over #0#0#args}
- REPEAT
- t:=t+Chr(Mem[startadd:i]);
- i:=Succ(i);
- UNTIL Mem[startadd:i]=0;
- StripPathname(t);
- Owner:=t;
-
- END; {owner}
-
- PROCEDURE WriteHooks(start,stop:Integer);
- {-show the trapped interrupt vectors}
- VAR
- v:Byte;
- vadd,sadd,eadd:Real;
-
- FUNCTION RealAdd(a:address):Real;
- {-return the real equivalent of an address (pointer)}
- BEGIN
- WITH a DO
- RealAdd:=16.0*Cardinal(segment)+Cardinal(offset);
- END{realadd};
-
- BEGIN
- sadd:=16.0*Cardinal(start);
- eadd:=16.0*Cardinal(stop);
- FOR v:=0 TO maxvector DO BEGIN
- vadd:=RealAdd(vectors[v]);
- IF (vadd>=sadd) AND (vadd<=eadd) THEN
- Write(Copy(Hex(v),3,2),' ');
- END;
- END{writehooks};
-
- PROCEDURE writemost;
- {-write most of the information about the memory block}
- BEGIN
- {.F-}
- Write(' ',
- Hex(mcbseg), ' ', {MCB address}
- Hex(pspadd), ' ', {PSP address}
- Hex(mcblen), ' ', {size of block in paragraphs}
- 16.0*Cardinal(mcblen):6:0, ' '); {size of block in bytes}
- {.F+}
-
- {get the program owning this block by scanning the environment}
- IF gotfirst THEN
- IF dosv>=3 THEN
- st:=Owner(MemW[pspadd:$2C])
- ELSE
- st:='N/A'
- ELSE
- st:='(DOS)';
- WHILE Length(st)<13 DO st:=st+' ';
- Write(st);
-
- END{writemost};
-
- PROCEDURE QueueSegs(pspadd:Integer;VAR prevseg,oldseg:Integer);
- {-push the PSP segments back through a 2 deep queue}
- BEGIN
- oldseg:=prevseg;
- prevseg:=pspadd;
- END{queuesegs};
-
- BEGIN {showtheblock}
-
- mcblen:=MemW[mcbseg:3];{size of the MCB in paragraphs}
- nextseg:=Succ(mcbseg+mcblen);{where the next MCB should be}
- pspadd:=MemW[mcbseg:1];{address of program segment prefix for MCB}
-
- IF showcandidates THEN BEGIN
- {show all potential MCBs without filtering techniques we employ below}
- LowVideo;
- writemost;
- Write(' ',Hex(nextseg),' ',Hex(Mem[nextseg:0]),' ');
- WriteLn;
- highvideo;
- END;
-
- IF (gotlast OR (Mem[nextseg:0]=$4D)) AND (pspadd<>0) THEN BEGIN
- {found part of MCB chain}
-
- IF gotlast OR (pspadd=prevseg) OR (pspadd=oldseg) THEN BEGIN
- {this is the MCB for the program, not for its environment}
- writemost;
- {show any interrupt vectors trapped by the program}
- IF gotfirst THEN WriteHooks(pspadd,nextseg);
- WriteLn;
- gotfirst:=True;
- END;
-
- QueueSegs(pspadd,prevseg,oldseg);
-
- END;
- END{showtheblock};
-
- BEGIN {main}
-
- WriteLn;
- WriteLn(' Allocated Memory Map');
- WriteLn;
- WriteLn('MCB adr PSP adr paras bytes owner hooked vectors');
- WriteLn('------- ------- ------- ------- ---------- ------------------------------');
-
- {start above the Basic work area, could probably start even higher}
- {there must be a magic address to start from, but it is not documented}
- mcbseg:=$50;
- prevseg:=0;
- oldseg:=0;
- gotfirst:=False;
- gotlast:=False;
- dosv:=DOSversion;
-
- {scan all memory until the last block is found}
- WHILE mcbseg<>$A000 DO BEGIN
- idbyte:=Mem[mcbseg:0];
- IF idbyte=midblockid THEN BEGIN
- {an allocated block}
- ShowTheBlock(mcbseg,prevseg,nextseg,gotfirst,gotlast);
- {search every paragraph boundary until first block is found}
- {then chain directly from block to block}
- IF gotfirst THEN mcbseg:=nextseg ELSE mcbseg:=Succ(mcbseg);
- END ELSE IF (idbyte=endblockid) AND gotfirst THEN BEGIN
- {last block, exit}
- gotlast:=True;
- ShowTheBlock(mcbseg,prevseg,nextseg,gotfirst,gotlast);
- mcbseg:=$A000;
- END ELSE
- {still looking for first block, try every paragraph boundary}
- mcbseg:=Succ(mcbseg);
- END;
-
- END.
-
-